//
//  SYDDataBase.m
//  CoreDataDemo
//
//  Created by 孙元东 on 2018/3/8.
//  Copyright © 2018年 MuJin. All rights reserved.
//

#import "SYDDataBase.h"
#import "Student+CoreDataClass.h"
#import <UIKit/UIKit.h>
#define MSYDDataBase [SYDDataBase sharedSYDDataBase]
@interface SYDDataBase()

//iOS9中 CoreData Stack核心的三个类
// 管理对象上下文  持久性存储模型数据  处理数据与应用的交互
@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext1;
//被管理对象模型
@property (nonatomic, strong) NSManagedObjectModel *objectModel;
//持久化存储调度器
@property (nonatomic, strong) NSPersistentStoreCoordinator *storeCoordinator;

//iOS10中NSPersistentContainer
/**
 CoreData Stack容器
 内部包含：
 管理对象上下文：NSManagedObjectContext *viewContext;
 对象管理模型：NSManagedObjectModel *managedObjectModel
 存储调度器：NSPersistentStoreCoordinator *persistentStoreCoordinator;
 */
@property(nonatomic,strong)NSPersistentContainer *persistentContainer;

@end
@implementation SYDDataBase

//单例的实现
SingletonM(SYDDataBase)
#pragma mark  =============lazy=================
#pragma mark -iOS9 CoreData Stack
//懒加载managedObjectModel
-(NSManagedObjectModel *)objectModel{
    if(_objectModel != nil){
        return _objectModel;
    }
    //根据某个模型文件路径创建模型文件
    // _managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:[[NSBundle mainBundle]URLForResource:@"Person" withExtension:@"momd"]];
    //合并Bundle所有.momd文件
    //budles: 指定为nil,自动从mainBundle里找所有.momd文件
    _objectModel = [NSManagedObjectModel mergedModelFromBundles:nil];
    
    return _objectModel;
}
//懒加载persistentStoreCoordinator
-(NSPersistentStoreCoordinator *)storeCoordinator{
    if(_storeCoordinator != nil){
        return _storeCoordinator;
    }
    //根据模型文件创建存储调度器
    _storeCoordinator = [[NSPersistentStoreCoordinator alloc]initWithManagedObjectModel:self.objectModel];
    return _storeCoordinator;
}

-(NSManagedObjectContext *)managedObjectContext1{
    // 返回已经绑定到`持久化存储调度器`的管理对象上下文
    if(_managedObjectContext1 != nil){
        return _managedObjectContext1;
    }
    //参数表示线程类型  NSPrivateQueueConcurrencyType比NSMainQueueConcurrencyType略有延迟
    _managedObjectContext1 = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSMainQueueConcurrencyType];
    return _managedObjectContext1;
}
#pragma mark -iOS10 CoreData Stack
//懒加载NSPersistentContainer
-(NSPersistentContainer *)persistentContainer{
    if(_persistentContainer != nil){
        return _persistentContainer;
    }
    //1.创建对象管理模型
    //    //根据某个模型文件路径创建模型文件
    //    NSManagedObjectModel *model = [[NSManagedObjectModel alloc] initWithContentsOfURL:[[NSBundle mainBundle]URLForResource:@"Person" withExtension:@"momd"]];
    
    //合并Bundle所有.momd文件
    //budles: 指定为nil,自动从mainBundle里找所有.momd文件
    NSManagedObjectModel *model = [NSManagedObjectModel mergedModelFromBundles:nil];
    //2.创建NSPersistentContainer
    /**
     * name:数据库文件名称
     */
    _persistentContainer = [[NSPersistentContainer alloc] initWithName:@"sql.db" managedObjectModel:model];
    
    //3.加载存储器
    [_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription * description, NSError * error) {
        NSLog(@"%@",description);
        NSLog(@"%@",error);
    }];
    
    return _persistentContainer;
}
#pragma mark - NSManagedObjectContext
//重写get方法
-(NSManagedObjectContext *)managedObjectContext{
    //获取系统版本
    float systemNum = [[UIDevice currentDevice].systemVersion floatValue];
    //根据系统版本返回不同的NSManagedObjectContext
    if(systemNum < 10.0)
    {
        return MSYDDataBase.managedObjectContext1;
    }
    else
    {
        return MSYDDataBase.persistentContainer.viewContext;
    }
}
- (NSPersistentContainer *)getCurrentPersistentContainer
{
    //获取系统版本
    float systemNum = [[UIDevice currentDevice].systemVersion floatValue];
    
    //根据系统版本返回不同的NSManagedObjectContext
    if(systemNum < 10.0)
    {
        return nil;
    }
    else
    {
        return MSYDDataBase.persistentContainer;
    }
}
- (void)save
{
    NSError *error = nil;
    [MSYDDataBase.managedObjectContext save:&error];
    if (error == nil) {
        NSLog(@"保存到数据库成功");
    }
    else
    {
        NSLog(@"保存到数据库失败：%@",error);
    }
}
//创建或者打开数据库
-(void)openOrCreateSqlite:(NSString *)sqliteName{
    
    
    //1、创建模型对象  --->self.objectModel
    //2、创建持久化存储助理：数据库   -->self.storeCoordinator
    //数据库的名称和路径
    NSString *sqlite = [NSString stringWithFormat:@"%@.sqlite",sqliteName];
    NSString *docStr = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *sqlPath = [docStr stringByAppendingPathComponent:sqlite];
    NSLog(@"数据库 path = %@", sqlPath);
    NSURL *sqlUrl = [NSURL fileURLWithPath:sqlPath];
    
    NSError *error = nil;
    //添加SQLite持久存储到解析器
        NSString *failurereason = @"there was an error creating or loading the application's saved data";
    //请求自动轻量级迁移
    NSDictionary *optionsDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
                                       [NSNumber numberWithBool:YES],
                                       NSMigratePersistentStoresAutomaticallyOption,
                                       [NSNumber numberWithBool:YES],
                                       NSInferMappingModelAutomaticallyOption, nil];
    //设置数据库相关信息 添加一个持久化存储库并设置类型和路径，NSSQLiteStoreType：SQLite作为存储库
    //NSMigratePersistentStoresAutomaticallyOption = YES，那么Core Data会试着把之前低版本的出现不兼容的持久化存储区迁移到新的模型中，这里的例子里，Core Data就能识别出是新表，就会新建出新表的存储区来。
    //NSInferMappingModelAutomaticallyOption = YES,这个参数的意义是Core Data会根据自己认为最合理的方式去尝试MappingModel，从源模型实体的某个属性，映射到目标模型实体的某个属性。
    if(![self.storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:sqlUrl options:optionsDictionary error:&error]){
        NSMutableDictionary *dict = [NSMutableDictionary dictionary];
        dict[NSLocalizedDescriptionKey] = failurereason;
    }
    [self.storeCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:sqlUrl options:optionsDictionary error:&error];
    if (error) {
        NSLog(@"打开数据库出错 - %@",error.localizedDescription);
    } else {
        NSLog(@"打开数据库成功!");
        //关联持久化助理
        self.managedObjectContext1.persistentStoreCoordinator = self.storeCoordinator;
    }
}
-(void)insertDataFromEntityName:(NSString *)name model:(Person *)model{
    
    // 1.根据Entity名称和NSManagedObjectContext获取一个新的继承于NSManagedObject的子类Student
    Student *student = [NSEntityDescription insertNewObjectForEntityForName:name inManagedObjectContext:self.managedObjectContext];
    //  2.根据表Student中的键值，给NSManagedObject对象赋值
    student.name = model.name;
    student.age = (int)model.age;
    student.sex = model.sex;
    student.weight = model.weight;
    student.number = (int)model.number;
    //保存操作
    if([self.managedObjectContext save:nil]){
        NSLog(@"数据插入成功");
    }else{
       NSLog(@"数据插入失败");
    }
}
-(NSArray *)readDataFromEntityName:(NSString *)name{
    //创建一个NSFetchRequest请求用于查询
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:name];
    //
    // 返回entityName的数据
    return [self.managedObjectContext executeFetchRequest:request error:nil];
}
-(void)deleteDataFromEntityName:(NSString *)name{
    // 创建一个NSFetchRequest请求用于查询
    NSFetchRequest * request = [NSFetchRequest fetchRequestWithEntityName:name];
    // 设置查询条件
    //request.predicate = [NSPredicate predicateWithFormat:[NSString stringWithFormat:@"recorde_type == %u",recordeType]];
    
    NSArray * array = [self.managedObjectContext executeFetchRequest:request error:nil];
    // 符合条件的删除
    for (Person * obj in array) {
        // 再删除当前的数据
        [self.managedObjectContext deleteObject:(NSManagedObject *)obj];
    }
    
    // 保存操作
    if ([self.managedObjectContext save:nil]) {
        NSLog(@"删除成功");
    }else{
        NSLog(@"删除失败");
    }
}
-(void)updateDataFromEntityName:(NSString *)name{
    //创建查询请求
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:name];
    
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"sex = %d",0];
    request.predicate = pre;
    
    //发送请求
    NSArray *resArray = [self.managedObjectContext executeFetchRequest:request error:nil];
    //修改
    for (Person *stu in resArray) {
        stu.name = @"且行且珍惜_iOS";
    }
    
    //保存
    NSError *error = nil;
    if ([self.managedObjectContext save:&error]) {
        NSLog(@"更新所有帅哥的的名字为“且行且珍惜_iOS”");
    }else{
        NSLog(@"更新数据失败, %@", error);
    }
}
-(NSArray *)sortDataFromEntityName:(NSString *)name{
    //创建排序请求
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:name];
    
    //实例化排序对象
    NSSortDescriptor *ageSort = [NSSortDescriptor sortDescriptorWithKey:@"age"ascending:YES];
    request.sortDescriptors = @[ageSort];

    //发送请求
    NSError *error = nil;
    NSArray *resArray = [self.managedObjectContext executeFetchRequest:request error:&error];
    
    if (error == nil) {
        NSLog(@"按照age排序");
    }else{
        NSLog(@"排序失败, %@", error);
    }
    return resArray;
}
-(NSArray *)getAllDataFromEntityName:(NSString *)name withCondition:(NSString *)condition{
    /* 谓词的条件指令
     1.比较运算符 > 、< 、== 、>= 、<= 、!=
     例：@"number >= 99"
     
     2.范围运算符：IN 、BETWEEN
     例：@"number BETWEEN {1,5}"
     @"address IN {'shanghai','nanjing'}"
     
     3.字符串本身:SELF
     例：@"SELF == 'APPLE'"
     
     4.字符串相关：BEGINSWITH、ENDSWITH、CONTAINS
     例：  @"name CONTAIN[cd] 'ang'"  //包含某个字符串
     @"name BEGINSWITH[c] 'sh'"    //以某个字符串开头
     @"name ENDSWITH[d] 'ang'"    //以某个字符串结束
     
     5.通配符：LIKE
     例：@"name LIKE[cd] '*er*'"   * 代表通配符,Like也接受[cd].
     @"name LIKE[cd] '???er*'"
     
     *注*: 星号 "*" : 代表0个或多个字符
     问号 "?" : 代表一个字符
     
     6.正则表达式：MATCHES
     例：NSString *regex = @"^A.+e$"; //以A开头，e结尾
     @"name MATCHES %@",regex
     
     注:[c]*不区分大小写 , [d]不区分发音符号即没有重音符号, [cd]既不区分大小写，也不区分发音符号。
     
     7. 合计操作
     ANY，SOME：指定下列表达式中的任意元素。比如，ANY children.age < 18。
     ALL：指定下列表达式中的所有元素。比如，ALL children.age < 18。
     NONE：指定下列表达式中没有的元素。比如，NONE children.age < 18。它在逻辑上等于NOT (ANY ...)。
     IN：等于SQL的IN操作，左边的表达必须出现在右边指定的集合中。比如，name IN { 'Ben', 'Melissa', 'Nick' }。
     
     提示:
     1. 谓词中的匹配指令关键字通常使用大写字母
     2. 谓词中可以使用格式字符串
     3. 如果通过对象的key
     path指定匹配条件，需要使用%K
     
     */
    //创建查询请求
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:name];
    //查询条件
    NSPredicate *pre = [NSPredicate predicateWithFormat:@"sex = %@",condition];
    request.predicate = pre;
    // 从第几页开始显示
    // 通过这个属性实现分页
    //request.fetchOffset = 0;
    
    // 每页显示多少条数据
    //request.fetchLimit = 6;
    //发送查询请求,并返回结果
    NSArray *resArray = [self.managedObjectContext executeFetchRequest:request error:nil];
    return resArray;
}
#pragma mark  =============Help=================
//获取沙盒路径URL
-(NSURL*)getDocumentsUrl
{
    //2.2 数据库的名称和路径
    return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] firstObject];
}

@end












